﻿#SingleInstance, Force
#NoTrayIcon
#NoEnv
SendMode Input
SetBatchLines, -1
DetectHiddenWindows On
SetWorkingDir %A_ScriptDir%  
#Include %A_ScriptDir%\lib\class_json.ahk
#Include %A_ScriptDir%\lib\ZipFile.ahk
#Include %A_ScriptDir%\lib\Functions.ahk
#Include %A_ScriptDir%\lib\UUIDCreate.ahk
Menu, Tray, Icon, %A_ScriptDir%\Icons\default.icl
IniRead, hGUI, %A_TEMP%\MZC, Auto, GUI
if WinExist("ahk_id " hGUI)
{
    MsgBox, 36, %cons_Title_QZA%, 当前QuickZ配置界面正在运行，是否强制关闭？
    ifMsgbox No
        return
    WinClose, ahk_id %hGUI%
}
ConfigFile := A_ScriptDir "\config.json"
if Not FileExist(ConfigFile)
    GenConfigJson()
g_qzConfig := Json.Parse(FileRead(ConfigFile))
QZAFile = %1%

if FileExist(QZAFile)
    GoSub, QZImport
else
    GoSub, QZExport
return

; =============================================
; 加载导入界面
; =============================================
QZImport:
cons_BTNOK := "确认(&O)"
cons_BTNClose := "关闭(&C)"
cons_BTNCancel := "取消(&C)"
cons_TextVarName := "变量名称(&N):"
cons_TextVarValue := "变量内容(&S):"
cons_IE_Title := "菜单项配置"
cons_IE_VarList := "名称|内容"
cons_IE_TitleVar := "选择变量"
cons_Title_QZA := "QZA管理器"

If RegExMatch(QZAFile, "i)\.json$")
{
    QZAJson := Json.Parse(FileRead(QZAFile))
}
If RegExMatch(QZAFile, "i)\.qza$")
{
    SplitPath, QZAFile, OutFileName, , , OutNameNoExt
    QZAFileTemp := A_Temp "\QZA_" OutNameNoExt
    QZAFileJson :=  QZAFileTemp "\qza.json"
    QZAFileZip := A_Temp "\" OutNameNoExt ".zip"
    FileCopy, %QZAFile%, %QZAFileZip%, 1
    If Fileexist(QZAFileTemp)
        FileRemoveDir, %QZAFileTemp%, 1
    FileCreateDir, %QZAFileTemp%
    ObjZip := ZipFile(QZAFileZip)
    ObjZip.unpack("*.*", QZAFileTemp)
    QZAJson := Json.Parse(FileRead(QZAFileJson))
    FileDelete, %QZAFileZip%
    FileDelete, %QZAFileJson%
}
;msgbox % Json.Stringify(QZAJson, 2)
Gui, QZImport: Destroy
Gui, QZImport: Default
Gui, QZImport: +theme -DPIScale +hwndhQZImport
Gui, QZImport: Font, s10, Microsoft YaHei
GUI, QZImport: Add, Button, x228 y460 w100  gQZImportToConfig, 导入配置(&A)
;GUI, QZImport: Add, Button, x120 y460 w100  gQZImportToConfig, 导入配置(&A)
;GUI, QZImport: Add, Button, x228 y460 w100  gQZImportToLibrary, 导入菜单库(&S)
GUI, QZImport: Add, Button, x335 y460 w70 gQZImportGUIClose, % cons_BTNClose
GUI, QZImport: Add, Tab2, x5 y5 w400 h450 , 说明|用户变量|文本正则
GUI, QZImport: Tab, 1
GUI, QZImport: Add, Groupbox, x15 y32 w380 h90
iName := QZAJson.QuickZApp.Name
iAuthor := QZAJson.QuickZApp.Author
iInfo := QZAJson.QuickZApp.info
GUI, QZImport: Add, Text, x20 y53 w350 h26, QZA名称：%iName%
GUI, QZImport: Add, Text, x20 y88 w350 h26, QZA作者：%iAuthor%
GUI, QZImport: Add, Edit, x15 y132 w380 h310 Readonly, %iInfo%
GUI, QZImport: Tab, 2
GUI, QZImport: Add, ListView, x15 y42 w380 h400 Grid checked AltSubmit Nosort gQZImport_LVEvent1, % cons_IE_VarList
GUI, QZImport: Tab, 3
GUI, QZImport: Add, ListView, x15 y42 w380 h400 Grid checked , 类型|说明|正则式
Gui, QZImport: Show, w410 h500,QZA 导入
ControlSend, Edit1, {End}, ahk_id %hQZImport%

GUI, QZImport: ListView, SysListView321
LV_ModifyCol(1,120)
LV_ModifyCol(2,300)
for VarKey , VarValue in QZAJson.user_env
    LV_Add("check", VarKey, VarValue )

GUI, QZImport: ListView, SysListView322
LV_ModifyCol(1,120)
LV_ModifyCol(2,180)
LV_ModifyCol(3,400)
Loop % QZAJson.text_regex.MaxIndex()
{
    iRegex := QZAJson.text_regex[A_Index]
    LV_Add("check", iRegex.name, iRegex.comment, iRegex.Regex)
}
return

QZImportGuiClose:
    FileRemoveDir, %QZAFileTemp%, 1
    ExitApp
return

QZImport_LVEvent1:
    GUI, QZImport: Default
    GUI, QZImport: ListView, SysListView321
    If A_GuiEvent = RightClick
    {
        ThisSelect := A_EventInfo
        LV_GetText(Varkey, ThisSelect, 1)
        LV_GetText(VarValue, ThisSelect, 2)
        GoSub, ItemEditor_VarMgr
        GuiControl, , Edit1, %VarKey%
        GuiControl, , Edit2, %VarValue%
    }
return

; 直接导入配置
QZImportToConfig:
    GoSub, QZImportVarAndRegex
    ; 导入内置菜单
    ObjDefault := {}
    ; 加载config.json中的内置菜单配置
    Loop % g_qzConfig.default.MaxIndex()
        ObjDefault[g_qzConfig.default[A_Index].name] := A_Index
    ; 开始添加
    Loop % QZAJson.default.MaxIndex()
    {
        thisFilterPos := A_Index
        thisFilter := QZAJson.default[thisFilterPos]
        thisName := thisFilter.name
        SaveFilter := g_qzConfig.default[ObjDefault[thisName]]
        Loop % thisFilter.SubItem.MaxIndex()
        {
            thisItem := thisFilter.SubItem[A_Index]
            if SaveFilter.SubItem.MaxIndex()
                SaveFilter.SubItem[SaveFilter.SubItem.MaxIndex()+1] := thisItem
            else
                SaveFilter.SubItem[1] := thisItem
        }
    }
    ; 导入文件菜单
    Loop % QZAJson.file.MaxIndex()
    {
        if g_qzConfig.file.MaxIndex()
            g_qzConfig.file[g_qzConfig.file.MaxIndex()+1] := QZAJson.file[A_Index]
        else
            g_qzConfig.file[1] := QZAJson.file[A_Index]
    }
    ; 导入文本菜单
    Loop % QZAJson.text.MaxIndex()
    {
        if g_qzConfig.text.MaxIndex()
            g_qzConfig.text[g_qzConfig.text.MaxIndex()+1] := QZAJson.text[A_Index]
        else
            g_qzConfig.text[1] := QZAJson.text[A_Index]
    }
    ; 导入窗口菜单
    Loop % QZAJson.class.MaxIndex()
    {
        if g_qzConfig.class.MaxIndex()
            g_qzConfig.class[g_qzConfig.class.MaxIndex()+1] := QZAJson.class[A_Index]
        else
            g_qzConfig.class[1] := QZAJson.class[A_Index]
        ;msgbox % Json.Stringify(g_qzConfig.class, 2)
    }
    qzConfigSave()
    ; 复制文件
    FileCopyDir, %QZAFileTemp%, %A_ScriptDir%, 1
    FileRemoveDir, %QZAFileTemp%, 1
    QZActionCheck()
    Send_WM_CopyData("Reload")
    Gui, QZImport: Destroy
    MsgBox, 32,, %QZAFile% 导入成功!
    ExitApp
return

; 直接导入菜单库
QZImportToLibrary:
    GoSub, QZImportVarAndRegex
    qzConfigSave()
return

; 保存变量和正则
QZImportVarAndRegex:
    GUI, QZImport: ListView, SysListView321
    RowNumber = 0  
    Loop
    {
        RowNumber := LV_GetNext(RowNumber, "Checked")  
        if not RowNumber  
            break
        LV_GetText(VarKey, RowNumber, 1)
        LV_GetText(VarValue, RowNumber, 2)
        g_qzConfig.user_env[VarKey] := VarValue
    }
    GUI, QZImport: ListView, SysListView322
    ObjText_Regex := {}
    Loop % g_qzConfig.text_regex.MaxIndex()
        ObjText_Regex[g_qzConfig.text_regex[A_Index].name] := A_Index
    RowNumber = 0  
    Loop
    {
        RowNumber := LV_GetNext(RowNumber, "Checked")  
        if not RowNumber  
            break
        LV_GetText(iName, RowNumber, 1)
        LV_GetText(iComment, RowNumber, 2)
        LV_GetText(iRegex, RowNumber, 3)
        if ObjText_Regex[iName]
        {
            g_qzConfig.text_regex[ObjText_Regex[iName]] := {name:iName, Comment: iComment, Regex: iRegex}
        }
        else
        {
            if g_qzConfig.text_regex.MaxIndex()
                g_qzConfig.text_regex[g_qzConfig.text_regex.MaxIndex()+1] := {name:iName, Comment: iComment, Regex: iRegex}
            else
                g_qzConfig.text_regex[1] := {name:iName, Comment: iComment, Regex: iRegex}
        }
    }
return

ItemEditor_VarMgr:
    Gui, ItemEditor_VarMgr: Destroy
    Gui, ItemEditor_VarMgr: Default
    Gui, ItemEditor_VarMgr: +theme -DPIScale
    Gui, ItemEditor_VarMgr: Font, s10, Microsoft YaHei
    Gui, ItemEditor_VarMgr: Add, Text, x10 y10 h24, % cons_TextVarName
    Gui, ItemEditor_VarMgr: Add, Edit, x10 y35 h24 w360 Readonly
    Gui, ItemEditor_VarMgr: Add, Text, x10 y65 h24, % cons_TextVarValue
    Gui, ItemEditor_VarMgr: Add, Edit, x10 y90 h24 w360 r6 vItemEditor_VarMgrValue -WantReturn,
    Gui, ItemEditor_VarMgr: Add, Button, x200 y220 h24 w80 gItemEditor_VarMgrOK, % cons_BTNOK
    Gui, ItemEditor_VarMgr: Add, Button, x290 y220 h24 w80 gItemEditor_VarMgrGUIClose, % cons_BTNCancel
    Gui, ItemEditor_VarMgr: Show, , % cons_IE_TitleVar
return
ItemEditor_VarMgrGUIEscape:
ItemEditor_VarMgrGUIClose:
    Gui, ItemEditor_VarMgr: Destroy
return
ItemEditor_VarMgrOK:
    GuiControlGet, VarKey, , Edit1
    GuiControlGet, VarValue, , Edit2
    GoSub, ItemEditor_VarMgrGUIClose
    GUI, QZImport: Default
    GUI, QZImport: ListView, SysListView321
    LV_Modify(ThisSelect, "focus", VarKey, VarValue)
return


!x::
reload
return

; =============================================
; 加载导出界面
; =============================================
QZExport:
cons_InsideMenu := "【内置菜单】===============================|"
cons_InsideMenuIcon := "%windir%\system32\shell32.dll:43"
cons_FileMenu := "【文件菜单】===============================|"
cons_FileMenuIcon := "%windir%\system32\shell32.dll:54"
cons_TextMenu := "【文本菜单】===============================|"
cons_TextMenuIcon := "%windir%\system32\shell32.dll:1"
cons_ClassMenu := "【窗口菜单】===============================|"
cons_ClassMenuIcon := "%windir%\system32\shell32.dll:2"
cons_FilterIcon := "%A_ScriptDir%\icons\default.icl:15"
cons_Separator := "--------------"

cons_Setting := "设置"
cons_SettingIcon := "%A_ScriptDir%\Icons\default.icl:25"

cons_HelpExport =
(
欢迎使用 QuickZ 导出功能！

一、关于QZA（QuickZ App）
      QuickZ App 是为了相互分享优秀的小程序、小脚本和高效率用法。作为QuickZ中的插件，其本质是一个“ZIP”文件，但是后缀名改成了 QZA 而已。QuickZ会专门进行处理和导入。

二、导出功能为3步：
1、设置要导出的菜单项。
2、设置要导出的文件。（分享程序、图标、脚本等）
3、给导出的QZA设定个好名字，还有分享的作者、详细的说明。如菜单对哪些文件类型有效等。越详细,帮助越大。

三、导出的内容
      除了导出为 *.qza 文件之外。为了方便共享，还支持导出为Json格式。但是Json格式有个比较明显的限制：不能带文件！Json格式非常适合在QQ群或者邮件或者网页上共享。点击导出为Json格式后，会保存为 *.json 文件，并且把内容复制到剪切板中，方便即时分享。

说明到此结束。Enjoy It ！ by Array
)
;3、设置菜单项配置涉及用户变量

QZExport_ObjSetting := {}
QZExport_ObjTop := {}
QZExport_ObjFilter := {}
QZExport_ObjMenu := {}
QZExport_ObjFile := {}
QZExport_ObjUserVar := {}
QZExport_ObjTextRegex := {}

Loop, % g_qzConfig.text_regex.MaxIndex()
    QZExport_ObjTextRegex[g_qzConfig.text_regex[A_Index].name] := {pos:A_Index, check:false}

if QZExport_ImgItem
    IL_Destroy(QZExport_ImgItem)
else
    QZExport_ImgItem := IL_Create(1,10,0)
if QZExport_ImgFile
    IL_Destroy(QZExport_ImgFile)
else
    QZExport_ImgFile := IL_Create(1,10,0)

QZExport_ImgItem_Icons := {}
QZExport_ImgFile_Icons := {}

GetExtIcon("Folder", iFile, iNum)
IL_Add(QZExport_ImgFile, ifile, iNum)

Gui, QZExport: Destroy
Gui, QZExport: Default
Gui, QZExport: +theme -DPIScale +hwndhQZExport
Gui, QZExport: Font, s10, Microsoft YaHei
GUI, QZExport: Add, Tab2, x5 y5 w400 h500 ,说明|菜单|文件|导出
GUI, QZExport: Add, Edit, x15 y40 w380 h455 Readonly, % cons_HelpExport
GUI, QZExport: Tab, 2
Gui, QZExport: Add, TreeView, Checked x15 y40 w380 h455 +hwndhQZExportItem AltSubmit ImageList%QZExport_ImgItem% -Lines 0x1000 gQZExport_TVEvent_Item
GUI, QZExport: Tab, 3
Gui, QZExport: Add, TreeView, Checked x15 y40 w380 h410 +hwndhQZExportFile AltSubmit ImageList%QZExport_ImgFile% gQZExport_TVEvent_File
GUI, QZExport: Add, Button, x295 y460 w100 gQZExport_Files_Add, 添加文件夹(&A)
GUI, QZExport: Tab, 4
;GUI, QZExport: Add, ListView, x15 y40 w380 h455 Grid, 变量名|内容
;GUI, QZExport: Tab, 5
GUI, QZExport: Add, Edit, x15 y40 w380, QZA:名称
GUI, QZExport: Add, Edit, x15 y75 w380, QZA:作者
GUI, QZExport: Add, Edit, x15 y110 w380 h340, QZA:说明/版本/相关信息
GUI, QZExport: Add, Button, x65 y460 w120 gQZExport_Json, 导出QZA://(&A)
GUI, QZExport: Add, Button, x195 y460 w120 gQZExport_QZA,  导出QZA文件(&S)
GUI, QZExport: Add, Button, x325 y460 w70 gQZExportGUIClose, 关闭(&C)
SetExplorerTheme(hQZExportItem)
SetExplorerTheme(hQZExportFile)
Gui, QZExport: Show, w410 h510, QZA 导出
ControlSend, Edit1, {end}, ahk_id %hQZExport%
Gui, QZExport: TreeView, SysTreeView321
QZExport_LoadSetting()
QZExport_Load(cons_InsideMenu, cons_InsideMenuIcon, "default")
QZExport_Load(cons_FileMenu, cons_FilterIcon, "file")
QZExport_Load(cons_TextMenu, cons_TextMenuIcon, "text")
QZExport_Load(cons_ClassMenu, cons_ClassMenuIcon, "class")
Gui, QZExport: TreeView, SysTreeView322
QZExport_Files(A_ScriptDir "\Apps")
QZExport_Files(A_ScriptDir "\Actions")
QZExport_Files(A_ScriptDir "\Docs")
QZExport_Files(A_ScriptDir "\Icons")
QZExport_Files(A_ScriptDir "\Lib")
QZExport_Files(A_ScriptDir "\Plugins")
return

QZExportGUIClose:
    ExitApp
return

QZExport_QZA:
  QZExport_Do()
return
QZExport_Json:
  if Strlen(qzaString := QZExport_Do(True))
  {
      GuiControlGet, QZA_Name,   , Edit2
      GuiControlGet, QZA_Author, ,Edit3
      GuiControlGet, QZA_Info,   , Edit4
      Clipboard := qzaString "`n`n!以下为说明，无需复制`n====================================`nQZA名称:" QZA_Name "`nQZA作者:" QZA_Author "`nQZA说明:"  QZA_Info "`n===================================="
  }
return

QZExport_TVEvent_Item:
    Gui, QZExport: default
    Gui, QZExport: TreeView, SysTreeView321
    If A_GuiEvent = Normal
        GoSub, QZExport_TVEvent
return

QZExport_TVEvent_File:
    Gui, QZExport: default
    Gui, QZExport: TreeView, SysTreeView322
    If A_GuiEvent = Normal
        GoSub, QZExport_TVEvent
return


QZExport_TVEvent:
    TV_Modify(A_EventInfo, "select")
    if TV_Get(A_EventInfo, "Check")
    {
        QZExport_TextFilter(QZExport_ObjFilter[A_EventInfo], "check", A_EventInfo)
        QZExport_UserVar(QZExport_ObjMenu[A_EventInfo].string, "check")
        QZExport_CheckSetting(A_EventInfo, "check")
        CheckParent(A_EventInfo, "Check")
        CheckChild(A_EventInfo, "Check")
    }
    else
    {
        QZExport_TextFilter(QZExport_ObjFilter[A_EventInfo], "-check", A_EventInfo)
        QZExport_UserVar(QZExport_ObjMenu[A_EventInfo].string, "-check")
        QZExport_CheckSetting(A_EventInfo, "-check")
        CheckChild(A_EventInfo, "-Check")
    }
return
; 加载父项
CheckParent(aID, opt)
{
    global QZExport_ObjMenu, QZExport_ObjFilter
    if (Parentid := TV_GetParent(aID))
    {
        TV_Modify(ParentID, opt)
        CheckParent(ParentID, opt)
        QZExport_TextFilter(QZExport_ObjFilter[ParentID], opt, ParentID)
        QZExport_UserVar(QZExport_ObjMenu[ParentID].string, opt)
        QZExport_CheckSetting(ParentID, opt)
    }
}
; 加载子项
CheckChild(aID, opt)
{
    global QZExport_ObjMenu, QZExport_ObjFilter
    if ( ChildID := TV_GetChild(aID) )
    {
        Loop
        {
            if ChildID
            {
                if ( SubChildID := TV_GetChild(ChildID) )
                    CheckChild(ChildID, opt)
                TV_Modify(ChildID, opt)
                QZExport_TextFilter(QZExport_ObjFilter[ChildID], opt, ChildID)
                QZExport_UserVar(QZExport_ObjMenu[ChildID].string, opt)
                QZExport_CheckSetting(ChildID, opt)
            }
            else
            {
                break
            }
            ChildID := TV_GetNext(ChildID)
        }
    }
}

QZExport_LoadSetting()
{
    global cons_Setting, cons_SettingIcon, QZExport_ObjTop, QZExport_ObjSetting, g_qzConfig
    opt := QZExport_TVOptions({icon:cons_SettingIcon})
    ParentID := TV_Add(cons_Setting, 0, "Expand " opt)
    QZExport_ObjTop[ParentID] := "setting"
    for name, var in g_qzConfig.Setting
        QZExport_ObjSetting[TV_Add(name, ParentID, opt)] := {name:name, option:false}
}


QZExport_Load(aName, aICON, aObjName)
{
    global QZExport_ObjTop, g_qzConfig
    aObj := g_qzConfig[aObjName]
    opt := QZExport_TVOptions({icon:aICON})
    SubID := TV_Add(aName, 0, opt " expand")
    QZExport_ObjTop[SubID] := aObjName
    QZExport_LoadSub(aObj, SubID, aLevel:=2)
    /*
    Loop % aObj.MaxIndex()
    {
        if aObj[a_index].id
        ;if isobject(aObj[a_index].subitem)
            ;QZExportAdd(aObj[a_index].subitem, SubID)
    }
    */
}
QZExport_LoadSub(aObjSub, aID, aLevel)
{
    global cons_FilterIcon, cons_Separator, QZExport_ObjFilter, QZExport_ObjMenu
    Static ItemNameAlias := { "Any": "通用菜单"
                          , "AnyFile": "任意文件"
                          , "AnyText": "任意文本"
                          , "AnyClass": "任意窗口"}
    Loop % aObjSub.MaxIndex()
    {
        Item := aObjSub[A_Index]
        if aLevel = 2
        {
            name := ItemNameAlias[Item.Name] ? ItemNameAlias[Item.Name] : Item.Name
            opt := QZExport_TVOptions({icon:cons_FilterIcon})
        }
        else
        {
            name := Item.name
            opt := QZExport_TVOptions(item.options)
        }
        if not strlen(item.id) and aLevel > 2
            TV_Add(cons_Separator, aID, opt)
        else
        {
           SubID := TV_Add(name, aID, opt)
           if aLevel = 2
               QZExport_ObjFilter[SubID] := Item
           else
               QZExport_ObjMenu[SubID] := Item
        }
        if IsObject(Item.SubItem)
          QZExport_LoadSub(Item.SubItem, SubID, aLevel+1)
    }
}

QZExport_TVOptions(aIcon)
{
    global QZExport_ImgItem, QZExport_ImgItem_Icons
    Opt := "" ;默认返回的TV控件的选项为空
    ; == 开始判断 TreeView 的图标选项 ==========
    icon := aIcon.icon
    if strlen(icon) ; icon 有效
    {
        if ic := QZExport_ImgItem_Icons[icon] ; 如果保存对象的QZExport_ImgItem_Icons中有对应的列表，则直接设置，无需判断
            opt_icon := "icon" ic
        else if RegExMatch(icon, ":[-\d]*$") ; example.exe:1 的格式
        {
            pos := RegExMatch(icon, ":[^:]*$")
		    file   := ReplaceEnv(SubStr(icon, 1, pos-1))
            Number := (number := substr(icon, pos+1)) > 0 ? Number + 1 : Number
            ic := IL_Add(QZExport_ImgItem, file, Number)
            if ic
            {
                Opt_icon := "icon" ic 
                QZExport_ImgItem_Icons[icon] := ic ; 保存到 QZExport_ImgItem_Icons 中，避免重复加载
            }
      }
	  else
      {
            file := ReplaceEnv(icon)   ; menuz.ico 的格式
            ic := IL_Add(QZExport_ImgItem, file)
            if ic
            {
                Opt_icon := "icon" ic 
                QZExport_ImgItem_Icons[icon] := ic ; 保存到 QZExport_ImgItem_Icons 中，避免重复加载
            }
      }
    }
    else
        opt_icon := "icon9999" 

    if not ic ; 如果无icon，必须设置为最大值，让图标为空
        opt_icon := "icon9999" 
    return opt_icon
    ; == 结束判断 TreeView 的图标选项 ==========
}

QZExport_Files_Add:
    FileSelectFolder, NewFolder, %A_ScriptDir%, 0, 请选择文件夹
    QZExport_Files(NewFolder)
return

QZExport_Files(aPath, aID=0)
{
    global QZExport_ObjFile
    SplitPath, aPath, filename
    ParentID := TV_Add(filename, aID, "icon" QZEX_GetIcon(aPath))
    QZExport_ObjFile[ParentID] := aPath
    Loop, %aPath%\*.*, 1
    {
        SplitPath, A_loopfilename, , , ext
        If (FileExist(A_loopfilefullpath), "D")
        {
            QZExport_Files(A_loopfilefullpath, ParentID)
        }
        else
        {
            PathID := TV_Add(A_loopfilename, ParentID, "icon" QZEX_GetIcon(A_loopfilename))
            QZExport_ObjFile[PathID] := A_loopfilefullpath
        }
    }
}


QZEX_GetIcon(aPath)
{
    global QZExport_ImgFile, QZExport_ImgFile_Icons
    if Instr(Fileexist(aPath),"D")
        return 1
    SplitPath, aPath, , , ext
    if QZExport_ImgFile_Icons[ext]
    {
        idx := QZExport_ImgFile_Icon[ext]
    }
    else
    {
        GetExtIcon("." ext, iFile, iNum)
        if instr(inum, "-")
            idx := IL_Add(QZExport_ImgFile, ifile, inum)
        else
            idx := IL_Add(QZExport_ImgFile, ifile, inum+1)
        QZExport_ImgFile_Icon[ext] := idx
    }
    return idx
}

QZExport_CheckSetting(aID, aOpt)
{
    global QZExport_ObjSetting, QZExport_ObjTop
    if (QZExport_ObjTop[TV_GetParent(aID)] = "setting")
    {
        if InStr(aOpt, "-")
            QZExport_ObjSetting[aID].option := False
        else
            QZExport_ObjSetting[aID].option := True
    }
}

QZExport_UserVar(aString, aOpt)
{
    global QZExport_ObjUserVar, g_qzConfig
    Gui, QZExport: default
    Gui, QZExport: ListView, SysListView321
    p1 := 1
    Loop 
    {
      p2 := RegExMatch(aString,"%[^%]*%",m,p1)
      If Not p2 
      {
        If P1 > 1
          r .= over
        Else
          r := aString
        Break
      }
      Else If Strlen(m)
      {
          ; 去掉找到的 %var% 两侧的 %
          env := SubStr(m,2,strlen(m)-2)
          if strlen(g_qzConfig.user_env[env])
          {
              if Instr(aOpt, "-")
              {
                  if QZExport_ObjUserVar[env]
                  {
                      /*
                      Loop % LV_GetCount()
                      {
                          LV_GetText(Text, A_Index, 1)
                          If ( Text = env )
                          {
                              LV_Delete(A_Index)
                              break
                          }
                      }
                      */
                      QZExport_ObjUserVar[env] := 0
                  }
              }
              else if not QZExport_ObjUserVar[env]
              {
                  ;LV_Add("", env, ReplaceEnv(m))
                  QZExport_ObjUserVar[env] := True
              }
          }
      }
      inter := SubStr(aString,p1,p2-p1)
      p1 := p2 + Strlen(m)
      over := SubStr(aString,p1)
    }
}

QZExport_TextFilter(aObj, aOpt, aID)
{
    global QZExport_ObjTextRegex, QZExport_ObjTop
    if (QZExport_ObjTop[TV_GetParent(aID)] = "text")
    {
        if IsObject(aObj)
        {
            iFilter := aObj.filter
            Loop, Parse, iFilter, `;
            {
                if not A_loopfield
                    Continue
                if Instr(aOpt, "-")
                    QZExport_ObjTextRegex[A_loopfield].check := false
                else
                    QZExport_ObjTextRegex[A_loopfield].check := true
            }
        }
    }
}

QZExport_Do(aJson=false)
{
    global QZExport_ObjTextRegex, QZExport_ObjUserVar, QZExport_ObjMenu, QZExport_ObjFilter, QZExport_ObjTop, QZExport_ObjFile, QZExport_ObjSetting, g_qzConfig
    QZA_Json := Json.Parse("{}")
    Gui, QZExport: Default
    GuiControlGet, QZA_Name,   , Edit2
    GuiControlGet, QZA_Author, ,Edit3
    GuiControlGet, QZA_Info,   , Edit4
    QZA_Json["QuickzApp"] := {Name:QZA_Name, Author:QZA_Author, Info:QZA_Info}
    Gui, QZExport: TreeView, SysTreeView321
    iTop := ""
    ;iFilter := ""
    iFilterIndex := 0
    iMenu := ""
    iMenuIndex := 0
    ItemID = 0  ; 这样使得首次循环从树的顶部开始搜索.
    Loop
    {
        ItemID := TV_GetNext(ItemID)
        if TV_Get(ItemID, "Check")
        {
            if (QZExport_ObjTop[ItemID] = "setting" )
            {
                QZA_Json["setting"] := {}
                ChildID := TV_GetChild(ItemID)
                Loop
                {
                    if not ChildID ; 没有更多项目了.
                        break
                    if TV_Get(ChildID, "Check")
                    {
                        set := QZExport_ObjSetting[ChildID].name
                        QZA_Json["setting"][set] := g_qzConfig.Setting[set]
                    }
                    ChildID := TV_GetNext(ChildID)
                }
            }
            else
                QZA_Json[QZExport_ObjTop[ItemID]] := QZExport_DoSub(ItemID)
        }
        if not ItemID  ; 没有更多项目了.
            break
    }

    ObjUser_Env := {} ; 用户变量
    for var, state in QZExport_ObjUserVar
    {
        if state
          ObjUser_Env[var] := g_qzConfig.user_env[var]
    }
    if strlen(var)
        QZA_Json["user_env"] := ObjUser_Env

    ObjText_Regex:= [] ; 文本匹配
    Index := 1
    for name, obj in QZExport_ObjTextRegex
    {
        if Obj.check
        {
            ObjText_Regex[Index] := g_qzConfig.text_regex[Obj.pos]
            Index++
        }
    }
    if Index > 1
        QZA_Json["text_regex"] := ObjText_Regex
    Jsontext := Json.stringify(QZA_Json, 2)
    TempDir := A_Temp "\QuickZ_QZA\"
    TempJson := TempDir "qza.json"
    PathTopack := TempDir "*.*"
    PathZip := A_Temp "\QuickzApp.zip"

    
    If Fileexist(TempDir)
        FileRemoveDir, %TempDir%, 1
    FileCreateDir, %TempDir%
    FileAppend, %Jsontext% , %TempJson%

    If aJson
    {
        Msgbox, 32, %cons_Title_QZA% ,QZA://文本已经复制到剪切板!
        return "QZA://" Json.stringify(QZA_Json)
        /*
        FileSelectFile, PathJson, S17, %A_ScriptDir%, 保存QZA Json, *.Json
        if strlen(PathJson)
        {
            if not RegExMatch(PathJson, "i)\.json$")
                PathJson .= ".json"
            FileMove, %TempJson%, %PathJson%, 1
            return "QZA://" Json.stringify(QZA_Json)
        }
        return
        */
    }

    Gui, QZExport: TreeView, SysTreeView322
    ItemID = 0  ; 这样使得首次循环从树的顶部开始搜索.
    Loop
    {
        ItemID := TV_GetNext(ItemID, "Checked")  ; 把 "Full" 替换为 "Checked" 来找出所有含复选标记的项目.
        if not ItemID  ; 没有更多项目了.
            break
        Pathfull := QZExport_ObjFile[ItemID]
        StringReplace, PathRelative, Pathfull, %A_ScriptDir%
        PathNew := TempDir . PathRelative
        If InStr(Fileexist(Pathfull), "D")
            FileCreateDir, %PathNew%
        else
            FileCopy, %Pathfull%, %PathNew%
    }
    if Fileexist(PathZip)
        FileDelete, %PathZip%
    ObjZip := Zipfile(PathZip)
    ObjZip.pack(PathTopack)
    FileSelectFile, PathQZA, S17, %A_ScriptDir%, 保存QZA, *.qza
    if strlen(PathQZA)
    {
        if not RegExMatch(PathQZA, "i)\.qza$")
            PathQZA .= ".qza"
        FileMove, %PathZip%, %PathQZA%, 1
    }
}

QZExport_DoSub(aID)
{
    global QZExport_ObjFilter, QZExport_ObjMenu
    ObjArray := []
    Index := 1
    ChildID := TV_GetChild(aID)
    Loop
    {
        if not ChildID ; 没有更多项目了.
            break
        if TV_Get(ChildID, "Check")
        {
            if IsObject(QZExport_ObjMenu[ChildID])
                ObjArray[Index] := IsObject(QZExport_ObjMenu[ChildID]) ? QZExport_ObjMenu[ChildID] : {}
            else
                ObjArray[Index] := IsObject(QZExport_ObjFilter[ChildID]) ? QZExport_ObjFilter[ChildID] : {}
            if TV_GetChild(ChildID)
                ObjArray[Index].SubItem := QZExport_DoSub(ChildID)
            Index++
        }
        ChildID := TV_GetNext(ChildID)
        ;msgbox % QZExport_ObjMenu[ChildID].name "`n" ChildID
    }
    return ObjArray
}

SetExplorerTheme(HCTL) 
{ ; HCTL : handle of a ListView or TreeView control
   If (DllCall("GetVersion", "UChar") > 5) {
      VarSetCapacity(ClassName, 1024, 0)
      If DllCall("GetClassName", "Ptr", HCTL, "Str", ClassName, "Int", 512, "Int")
         If (ClassName = "SysListView32") || (ClassName = "SysTreeView32")
            Return !DllCall("UxTheme.dll\SetWindowTheme", "Ptr", HCTL, "WStr", "Explorer", "Ptr", 0)
   }
   Return False
}
